package main

import (
	"context"
	"fmt"
	"io/ioutil"
	"log"
	"strings"
	"unicode/utf8"

	"go-file-perception-model/internal/config"
	"go-file-perception-model/internal/logger"
	"go-file-perception-model/internal/service"
)

// SimpleEmbeddingModel 简单的嵌入模型实现
type SimpleEmbeddingModel struct{}

func (m *SimpleEmbeddingModel) Embedding(ctx context.Context, text string) ([]float32, error) {
	// 返回一个固定大小的向量用于测试
	return make([]float32, 768), nil
}

func (m *SimpleEmbeddingModel) BatchEmbedding(ctx context.Context, texts []string) ([][]float32, error) {
	// 返回固定大小的向量数组用于测试
	result := make([][]float32, len(texts))
	for i := range texts {
		result[i] = make([]float32, 768)
	}
	return result, nil
}

func (m *SimpleEmbeddingModel) Close() error {
	return nil
}

func (m *SimpleEmbeddingModel) GetModelInfo() map[string]interface{} {
	return map[string]interface{}{
		"model_name": "simple_model",
		"dimension":  768,
	}
}

// ensureUTF8 确保文本是有效的UTF-8编码
func ensureUTF8(content []byte) string {
	// 如果已经是有效的UTF-8编码，直接返回
	if utf8.Valid(content) {
		return string(content)
	}

	// 如果不是有效的UTF-8编码，尝试修复
	// 方法3: 使用简单的方法：替换无效的UTF-8序列为Unicode替换字符
	var result []rune
	for i := 0; i < len(content); {
		r, size := utf8.DecodeRune(content[i:])
		if r == utf8.RuneError && size == 1 {
			// 无效的UTF-8序列，添加替换字符
			result = append(result, utf8.RuneError)
			i++
		} else {
			result = append(result, r)
			i += size
		}
	}
	return string(result)
}

// calculateLineNumber 计算指定位置在文本中的行号
func calculateLineNumber(text string, pos int) int {
	if pos < 0 || pos >= len(text) {
		return 1
	}

	// 确保pos位于UTF-8字符边界上
	adjustedPos := findNearestUTF8Boundary(text, pos)

	// 计算行号
	lineNumber := 1
	for i := 0; i < adjustedPos; i++ {
		if text[i] == '\n' {
			lineNumber++
		}
	}

	return lineNumber
}

// findNearestUTF8Boundary 查找最近的UTF-8字符起始位置
func findNearestUTF8Boundary(text string, pos int) int {
	// 如果pos已经是UTF-8字符边界，直接返回
	if pos <= 0 || pos >= len(text) {
		return pos
	}

	// 向前查找UTF-8字符边界
	for i := pos; i > 0; i-- {
		// 检查当前位置是否是UTF-8字符的起始字节
		b := text[i]
		if (b & 0xC0) != 0x80 {
			// 这是UTF-8字符的起始字节
			return i
		}
	}

	return 0
}

func main() {
	// 初始化logger
	logger.InitLogger()
	
	// 创建测试配置
	cfg := &config.FileIndexConfig{
		ChunkSize:        200,  // 设置较小的分块大小以便产生多个分块
		ChunkOverlap:     50,   // 设置重叠大小
		SemanticChunking: false, // 使用固定大小分块
		MaxChunkSize:     500,
		MinChunkSize:     50,
		SummaryLength:    100,
	}

	// 创建文件处理器
	embeddingModel := &SimpleEmbeddingModel{}
	processor := service.NewFileProcessor(embeddingModel, cfg)

	// 测试文件路径
	filePath := "d:\\2025年项目\\技术类项目\\go文件感知国产模型\\test\\testfile_with_numbers.txt"

	// 处理文件
	chunks, err := processor.ProcessFile(filePath)
	if err != nil {
		log.Fatalf("Failed to process file: %v", err)
	}

	if len(chunks) == 0 {
		log.Fatal("No chunks were generated")
	}

	// 读取原始文件内容以进行验证
	content, err := ioutil.ReadFile(filePath)
	if err != nil {
		log.Fatalf("Failed to read file: %v", err)
	}
	text := ensureUTF8(content)

	// 将文件内容按行分割，以便验证行号
	lines := strings.Split(text, "\n")

	fmt.Printf("Total chunks: %d\n", len(chunks))
	fmt.Printf("Total lines in file: %d\n", len(lines))
	fmt.Println("\nChunk details:")

	// 验证每个分块的行号
	allLineNumbersMatch := true
	for _, chunk := range chunks {
		// 验证StartLine和EndLine是否正确
		if chunk.StartLine < 1 || chunk.EndLine < chunk.StartLine || chunk.EndLine > len(lines) {
			fmt.Printf("ERROR: Invalid line numbers in chunk %d: StartLine=%d, EndLine=%d\n", 
				chunk.ChunkNo, chunk.StartLine, chunk.EndLine)
			allLineNumbersMatch = false
			continue
		}

		// 获取分块内容
		chunkContent := chunk.Content

		// 验证行号计算是否正确
		// 使用calculateLineNumber方法重新计算StartPos和EndPos对应的行号
		calculatedStartLine := calculateLineNumber(text, chunk.StartPos)
		calculatedEndLine := calculateLineNumber(text, chunk.EndPos-1)

		// 验证计算的行号是否与分块中的行号一致
		if chunk.StartLine != calculatedStartLine || chunk.EndLine != calculatedEndLine {
			fmt.Printf("ERROR: Line number mismatch in chunk %d: ", chunk.ChunkNo)
			fmt.Printf("Expected StartLine=%d, EndLine=%d; ", calculatedStartLine, calculatedEndLine)
			fmt.Printf("Got StartLine=%d, EndLine=%d\n", chunk.StartLine, chunk.EndLine)
			allLineNumbersMatch = false
			continue
		}

		// 获取原始文件中对应行号范围的内容
		var originalContent string
		for i := chunk.StartLine; i <= chunk.EndLine && i <= len(lines); i++ {
			// 去除行号前缀（格式为 "数字: "）
			line := lines[i-1]
			if len(line) > 0 {
				// 找到第一个冒号的位置
				if colonPos := strings.Index(line, ":"); colonPos > 0 {
					// 跳过冒号和可能的空格
					contentStart := colonPos + 1
					if contentStart < len(line) && line[contentStart] == ' ' {
						contentStart++
					}
					line = line[contentStart:]
				}
			}
			originalContent += line
			if i < chunk.EndLine && i < len(lines) {
				originalContent += "\n"
			}
		}

		// 验证分块内容是否与原始文件内容匹配
		// 注意：由于分块可能在行中间，所以不能直接比较整个字符串
		// 我们只验证分块内容是否是原始文件内容的子串
		if !strings.Contains(text, chunkContent) {
			fmt.Printf("ERROR: Chunk content not found in original file in chunk %d\n", chunk.ChunkNo)
			allLineNumbersMatch = false
			continue
		}

		// 打印调试信息
		fmt.Printf("Chunk %d: StartLine=%d, EndLine=%d, StartPos=%d, EndPos=%d, Length=%d - OK\n",
			chunk.ChunkNo, chunk.StartLine, chunk.EndLine, chunk.StartPos, chunk.EndPos, len(chunk.Content))
	}

	// 验证所有分块是否覆盖了整个文件
	// 检查第一个分块是否从文件开头开始
	if len(chunks) > 0 {
		if chunks[0].StartPos != 0 {
			fmt.Printf("ERROR: First chunk should start at position 0, but starts at %d\n", chunks[0].StartPos)
			allLineNumbersMatch = false
		}
		if chunks[0].StartLine != 1 {
			fmt.Printf("ERROR: First chunk should start at line 1, but starts at %d\n", chunks[0].StartLine)
			allLineNumbersMatch = false
		}
	}

	// 检查最后一个分块是否到达文件末尾
	if len(chunks) > 0 {
		lastChunk := chunks[len(chunks)-1]
		if lastChunk.EndPos != len(text) {
			fmt.Printf("ERROR: Last chunk should end at position %d, but ends at %d\n", len(text), lastChunk.EndPos)
			allLineNumbersMatch = false
		}
		if lastChunk.EndLine != len(lines) {
			fmt.Printf("ERROR: Last chunk should end at line %d, but ends at %d\n", len(lines), lastChunk.EndLine)
			allLineNumbersMatch = false
		}
	}

	// 验证分块之间的连续性
	for i := 1; i < len(chunks); i++ {
		prevChunk := chunks[i-1]
		currChunk := chunks[i]
		// 由于有重叠，所以当前分块的StartPos应该小于前一个分块的EndPos
		if currChunk.StartPos > prevChunk.EndPos {
			fmt.Printf("ERROR: Gap between chunks %d and %d\n", i-1, i)
			allLineNumbersMatch = false
		}
	}

	if allLineNumbersMatch {
		fmt.Println("\nSUCCESS: All line numbers match correctly!")
	} else {
		fmt.Println("\nFAILURE: Some line numbers do not match correctly.")
	}

	// 测试语义分块
	fmt.Println("\n\nTesting semantic chunking...")
	cfg.SemanticChunking = true
	processor2 := service.NewFileProcessor(embeddingModel, cfg)

	// 处理文件
	chunks2, err := processor2.ProcessFile(filePath)
	if err != nil {
		log.Fatalf("Failed to process file with semantic chunking: %v", err)
	}

	if len(chunks2) == 0 {
		log.Fatal("No semantic chunks were generated")
	}

	fmt.Printf("Total semantic chunks: %d\n", len(chunks2))
	fmt.Println("\nSemantic chunk details:")

	// 验证每个语义分块的行号
	allSemanticLineNumbersMatch := true
	for _, chunk := range chunks2 {
		// 验证StartLine和EndLine是否正确
		if chunk.StartLine < 1 || chunk.EndLine < chunk.StartLine || chunk.EndLine > len(lines) {
			fmt.Printf("ERROR: Invalid line numbers in semantic chunk %d: StartLine=%d, EndLine=%d\n", 
				chunk.ChunkNo, chunk.StartLine, chunk.EndLine)
			allSemanticLineNumbersMatch = false
			continue
		}

		// 验证行号计算是否正确
		// 使用calculateLineNumber方法重新计算StartPos和EndPos对应的行号
		calculatedStartLine := calculateLineNumber(text, chunk.StartPos)
		calculatedEndLine := calculateLineNumber(text, chunk.EndPos-1)

		// 验证计算的行号是否与分块中的行号一致
		if chunk.StartLine != calculatedStartLine || chunk.EndLine != calculatedEndLine {
			fmt.Printf("ERROR: Line number mismatch in semantic chunk %d: ", chunk.ChunkNo)
			fmt.Printf("Expected StartLine=%d, EndLine=%d; ", calculatedStartLine, calculatedEndLine)
			fmt.Printf("Got StartLine=%d, EndLine=%d\n", chunk.StartLine, chunk.EndLine)
			allSemanticLineNumbersMatch = false
			continue
		}

		// 打印调试信息
		fmt.Printf("Semantic Chunk %d: StartLine=%d, EndLine=%d, StartPos=%d, EndPos=%d, Length=%d - OK\n",
			chunk.ChunkNo, chunk.StartLine, chunk.EndLine, chunk.StartPos, chunk.EndPos, len(chunk.Content))
	}

	if allSemanticLineNumbersMatch {
		fmt.Println("\nSUCCESS: All semantic chunk line numbers match correctly!")
	} else {
		fmt.Println("\nFAILURE: Some semantic chunk line numbers do not match correctly.")
	}
}